梦想不会自己发光,真正闪耀的是那个为梦狂奔的你。献给知行的孩子们!(Eric.He著)
栈(Stack)是数据结构中经典的后进先出(LIFO, Last In, First Out),也可称为 “先进后出(FILO)”,就像日常生活中的米桶最先进入的大米最后才被拿出来。栈(Stack)是一种线性数据结构,它的存储方式遵循 “有序线性” 的特征(数据元素之间存在一对一的前后逻辑关系),但访问和操作具有严格的限制性。本教程基于链表实现的栈,从核心原理、代码结构到实战使用,全面讲解栈的原理与实现,功能包含入栈、出栈、获取栈顶元素等核心功能。
| 操作名称 | 功能描述 | 时间复杂度 |
|---|---|---|
| 入栈 | 将指定元素添加到栈顶,栈满时抛出异常或返回失败标识 | O(1) |
| 出栈 | 从栈顶移除并返回元素,栈为空时抛出异常或返回失败标识 | O(1) |
| 判空 | 判断栈是否为空,返回布尔值(true = 空,false = 非空) | O(1) |
| 判满 | 判断固定容量队列是否已满,返回布尔值(true = 满,false = 未满)(链式栈无需此操作) | O(1) |
| 获取栈顶元素 | 查看栈顶元素的值,不执行移除操作,栈为空时抛出异常或返回无效值 | O(1) |
栈可以采用顺序存储和链式存储两种形式:
每一个节点有二个域,即data数据域、next下一个节点地址。
提供的代码是模板化的栈实现(支持任意类型),采用C++结构体封装,分为头文件(声明)和源文件(实现)两部分,核心结构如下:
| 模块 | 作用 | 关键结构/函数 |
|---|---|---|
| 节点结构体 | 存储数据、下一个节点地址 | StackNode<T>(模板泛型) |
| 栈结构体 | 封装所有操作 | LinkedStack<T>(模板类) |
template <typename T>
struct StackNode
{
T data; //栈节点数据
StackNode* next; //下一个栈节点指针
};
template <typename T>
struct LinkedStack{
// ------------------------------------------------------------------------------------------------------
// 私有成员
// 注:私有成员只能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)不能访问调用)
//------------------------------------------------------------------------------------------------------
private:
//---------------声明私有成员变量---------------
StackNode<T> *top = nullptr; // 栈顶指针
//---------------声明私有成员函数---------------
// ------------------------------------------------------------------------------------------------------
// 公共成员
// 注:公共成员能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)也能访问调用)
//------------------------------------------------------------------------------------------------------
public:
//---------------声明公共成员函数---------------
// 构造函数:外部通过该结构体定义(实例化)变量(对象)时,自动执行该函数(主要用于初始化成员变量的值)
LinkedStack() {
top = nullptr;
}
int isEmpty(); // 判断栈是否为空
T getTop(); // 获取栈顶元素(不弹出)
void push(const T& value); // 入栈
T pop(); // 出栈
void deleteStack(); // 手动释放内存
void print(); // 打印栈数据(从栈底到栈顶,不修改top指针)
// 析构函数:自动销毁栈,避免内存泄漏
~LinkedStack() {
deleteStack();
}
};
int、float、自定义类型等任意类型(需重载比较运算符);template <typename T>
T LinkedStack<T>::getTop() {
if (isEmpty()) {
return T();
}
return top->data;
}
template <typename T>
void LinkedStack<T>::push(const T& value)
{
StackNode<T> *p = new StackNode<T>;
p->data = value;
p->next = top;
top = p;
}
template <typename T>
T LinkedStack::pop()
{
T value;
StackNode<T> *p = top;
if(top != nullptr)
{
p = top;
value = p->data;
top = p->next;
delete(p);
return value;
}
else
{
printf("栈为空!\n");
return T();
}
}
#include "LinkedStack.h"
#include <iostream>
int main() {
LinkedStack<int> stacks;
// 1. 入栈测试
printf("\n=== 入栈测试 ===\n");
stacks.push(1);
stacks.push(2);
stacks.push(3);
stacks.push(4);
stacks.push(5);
printf("入栈1、2、3、4、5后:\n");
stacks.print();
// 2. 出队测试
printf("\n=== 出栈测试 ===\n");
printf("出栈3次:");
printf("%d ",stacks.pop());
printf("%d ",stacks.pop());
printf("%d \n",stacks.pop());
printf("出栈后");
stacks.print();
return 0;
}
=== 入栈测试 ===
入栈1、2、3、4、5后:
栈元素(栈底 → 栈顶):1 2 3 4 5
=== 出栈测试 ===
出栈3次:5 4 3
出栈后栈元素(栈底 → 栈顶):1 2
#ifndef ENTITYS_H_INCLUDED
#define ENTITYS_H_INCLUDED
//************************************************************************************************************************************************************************
// 自定义类型
//************************************************************************************************************************************************************************
//========================================================================================================================================================================
// 学生结构体(Student)
//========================================================================================================================================================================
struct Student {
int id;// 学号
std::string name;// 姓名
std::string dob;// 出生日期
std::string sex;// 性别
std::string gender;// 民族
std::string address;// 地址
float score;// 入学总分
std::string school;// 学校
std::string team;// 班级
std::string status;// 状态
bool operator<(const Student& other) const { return id < other.id; }
bool operator>(const Student& other) const { return id > other.id; }
bool operator==(const Student& other) const { return id == other.id; }
bool operator!=(const Student& other) const { return id != other.id; }
friend std::ostream& operator<<(std::ostream& os, const Student& s) {
os << "[" << s.id<< ", " << s.name << ", " << s.dob << ", " << s.sex << ", " << s.gender << ", " << s.address << ", " << s.score<< ", " << s.school<< ", " << s.team<< ", " << s.status << "]";
return os;
}
};
//========================================================================================================================================================================
//
// 学生索引结构体(Student)
//
//========================================================================================================================================================================
struct StudentIndex {
int id;// 学号
int row;// 行号
bool operator<(const StudentIndex& other) const { return id < other.id; }
bool operator>(const StudentIndex& other) const { return id > other.id; }
bool operator==(const StudentIndex& other) const { return id == other.id; }
bool operator!=(const StudentIndex& other) const { return id != other.id; }
friend std::ostream& operator<<(std::ostream& os, const StudentIndex& i) {
os << "[" << i.id << ", " << i.row<< "]";
return os;
}
};
//========================================================================================================================================================================
// 迷宫坐标结构体(Pos)
//========================================================================================================================================================================
struct Pos{
int x; //x坐标
int y; //y坐标
int step; //步数
};
//========================================================================================================================================================================
// 打印任务结构体(PrintTask)
//========================================================================================================================================================================
struct PrintTask{
int taskId; // 任务ID
char content[50]; // 打印内容
};
#endif // ENTITYS_H_INCLUDED
#ifndef LINKEDSTACK_H_INCLUDED
#define LINKEDSTACK_H_INCLUDED
#include "Entitys.h"
//************************************************************************************************************************************************************************
//
// 类名:链表栈(LinkedStack)
//
// 概述:一个可复用的链表栈,存储结构采用链表实现,支持任意类型数据(模板泛型)。
//
// 说明:采用链表存储结构,栈的容量没限制,入栈出栈时间复杂度为O(1)
//
//************************************************************************************************************************************************************************
//========================================================================================================================================================================
//
// 栈节点结构体(StackNode)
//
//========================================================================================================================================================================
template <typename T>
struct StackNode
{
T data; //栈节点数据
StackNode* next; //下一个栈节点指针
};
//========================================================================================================================================================================
//
// 链表栈结构体(LinkedStack)
//
//========================================================================================================================================================================
template <typename T>
struct LinkedStack{
// ------------------------------------------------------------------------------------------------------
// 私有成员
// 注:私有成员只能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)不能访问调用)
//------------------------------------------------------------------------------------------------------
private:
//---------------声明私有成员变量---------------
StackNode<T> *top = nullptr; // 栈顶指针
//---------------声明私有成员函数---------------
// ------------------------------------------------------------------------------------------------------
// 公共成员
// 注:公共成员能在该结构体内部访问调用,外部通过该结构体定义(实例化)的变量(对象)也能访问调用)
//------------------------------------------------------------------------------------------------------
public:
//---------------声明公共成员函数---------------
// 构造函数:外部通过该结构体定义(实例化)变量(对象)时,自动执行该函数(主要用于初始化成员变量的值)
LinkedStack() {
top = nullptr;
}
int isEmpty(); // 判断栈是否为空
T getTop(); // 获取栈顶元素(不弹出)
void push(const T& value); // 入栈
T pop(); // 出栈
void deleteStack(); // 手动释放内存
void print(); // 打印栈数据(从栈底到栈顶,不修改top指针)
// 析构函数:自动销毁栈,避免内存泄漏
~LinkedStack() {
deleteStack();
}
};
#endif // LINKEDSTACK_H_INCLUDED
#include <iostream>
#include"LinkedStack.h"
//---------------实现公共成员函数---------------
// 判断栈是否为空
template <typename T>
int LinkedStack<T>::isEmpty() {
return top == nullptr;
}
// 获取栈顶元素(不弹出)
template <typename T>
T LinkedStack<T>::getTop() {
if (isEmpty()) {
return T();
}
return top->data;
}
//入栈
template <typename T>
void LinkedStack<T>::push(const T& value)
{
StackNode<T> *p = new StackNode<T>;
p->data = value;
p->next = top;
top = p;
}
//出栈
template <typename T>
T LinkedStack<T>::pop()
{
T value;
StackNode<T> *p = top;
if(top != nullptr)
{
p = top;
value = p->data;
top = p->next;
delete(p);
return value;
}
else
{
printf("栈为空!\n");
return T();
}
}
// 释放内存
template <typename T>
void LinkedStack<T>::deleteStack() {
while(top != nullptr)
{
StackNode<T> *p = top;
top = p->next;
delete(p);
}
top = nullptr;
}
// 打印栈数据(从栈底到栈顶,不修改top指针)
template <typename T>
void LinkedStack<T>::print() {
if (isEmpty()) {
printf("栈为空,无元素可打印!\n");
return;
}
// 核心逻辑:链表栈仅能从栈顶遍历,需借助临时栈反转后打印(保证不修改原栈)
LinkedStack tempStack; // 临时栈,用于反转元素
StackNode<T>* curr = top;
// 第一步:将原栈元素暂存到临时栈(原栈顶 → 临时栈底)
while (curr != nullptr) {
tempStack.push(curr->data);
curr = curr->next;
}
// 第二步:遍历临时栈(从栈顶到栈底 = 原栈的栈底到栈顶)
printf("栈元素(栈底 → 栈顶):");
curr = tempStack.top;
while (curr != nullptr) {
printf("%d ", curr->data);
curr = curr->next;
}
printf("\n");
// 可选:补充打印栈顶→栈底(直接遍历原栈即可)
/*printf("栈元素(栈顶 → 栈底):");
curr = top;
while (curr != nullptr) {
printf("%d ", curr->data);
curr = curr->next;
}
printf("\n");*/
// 释放临时栈内存(避免泄漏)
tempStack.deleteStack();
}
// 显式实例化常用类型(避免链接错误,可选)
template class LinkedStack<int>;
template class LinkedStack<char>;
template class LinkedStack<float>;
template class LinkedStack<std::string>;
template class LinkedStack<Student>; // 新增:显式实例化Student类型
template class LinkedStack<PrintTask>; // 新增:显式实例化PrintTask类型
template class LinkedStack<Pos>; // 新增:显式实例化Pos类型
#include "LinkedStack.h"
#include <iostream>
#include <string>
int main() {
LinkedStack<int> stacks;
// 1. 入栈测试
printf("\n=== 入栈测试 ===\n");
stacks.push(1);
stacks.push(2);
stacks.push(3);
stacks.push(4);
stacks.push(5);
printf("入栈1、2、3、4、5后:\n");
stacks.print();
// 2. 出队测试
printf("\n=== 出栈测试 ===\n");
printf("出栈3次:");
printf("%d ",stacks.pop());
printf("%d ",stacks.pop());
printf("%d \n",stacks.pop());
printf("出栈后");
stacks.print();
return 0;
}
=== 入栈测试 ===
入栈1、2、3、4、5后:
栈元素(栈底 → 栈顶):1 2 3 4 5
=== 出栈测试 ===
出栈3次:5 4 3
出栈后栈元素(栈底 → 栈顶):1 2
模板类型约束:
</>/==运算符(内置类型如int/string默认支持,自定义类型需重载);<<运算符(打印输出时使用)。显式实例化:代码末尾的template class LinkedQueue<int>;等显式实例化,避免链接错误,新增类型需补充显式实例化。
本教程通过代码解析和实战示例,覆盖了栈的核心原理、关键操作实现和实际使用场景。栈作为基础数据结构,掌握栈的实现,是深入学习更复杂数据结构的重要基础。